package subjects

import (
	"binseek/pkg/finder"
	"binseek/pkg/utils"
	"bytes"
)

type IpWry struct { // CNZZ设计的纯真IP格式
	*finder.Pandect
}

func NewIpWry(fileName string) (*IpWry, error) {
	pand, err := finder.NewPandect(fileName, 3, false)
	if err != nil {
		return nil, err
	}
	wry, posLst := &IpWry{pand}, make([]int64, 2)
	if posLst, err = pand.ReadPositions(false); err != nil {
		return wry, err
	}
	lastPos, firstPos := posLst[0], posLst[1]
	fixSize := int(wry.FileSize - lastPos)
	indexSize := int(lastPos-firstPos) + fixSize
	err = wry.CreateIndex(fixSize, indexSize, firstPos)
	return wry, err
}

func (p *IpWry) GetRecord() (infoA, infoB []byte, err error) { // 纯真IP库格式记录
	utils.DebugPrint("GetRecord:")
	n, i, pSize := 0, 0, p.JumpSize+1
	head := make([]byte, pSize)
	n, err = p.Read(head)
	utils.DebugPrint("head", head)
	if err != nil || n <= 0 {
		return
	}
	var data []byte
	flag := finder.ReadFlag(utils.FirstByte(head))
	if flag == finder.ReadForward {
		utils.DebugPrint("ReadForward:")
		i, data, err = p.AheadRead(0, finder.RECORD_MAX_SIZE, finder.ReadForward)
		utils.DebugPrint("ReadForward data", data)
		infoA, err = p.JumpRead(head[1:pSize], 0, finder.RECORD_MAX_SIZE, finder.ReadForward)
		flag = finder.ReadFlag(utils.FirstByte(data))
		if flag == finder.ReadForward || flag == finder.ReadOnward {
			if n = len(data); n > pSize {
				n = pSize
			}
			infoB, err = p.JumpRead(data[1:n], 0, finder.RECORD_MAX_SIZE, finder.ReadForward)
		} else {
			infoB = data
		}
	} else if flag == finder.ReadOnward {
		utils.DebugPrint("ReadOnward:")
		if err = p.JumpTo(head[1:pSize], []byte{0x00}, false); err == nil {
			infoA, infoB, err = p.GetRecord()
		}
	} else {
		utils.DebugPrint("JumpFinal:")
		if i = bytes.IndexByte(head, 0x00); i >= 0 {
			_, data, err = p.AheadRead(0, finder.RECORD_MAX_SIZE, finder.ReadForward)
			infoA, infoB = head[:i], append(head[i+1:], data...)
		} else {
			i, data, err = p.AheadRead(0, finder.RECORD_MAX_SIZE, finder.ReadOnward)
			infoA, infoB = append(head, data[:i]...), data[i+1:]
		}
		flag = finder.ReadFlag(utils.FirstByte(infoB))
		if flag == finder.ReadForward {
			if n = len(infoB); n > pSize {
				n = pSize
			}
			infoB, err = p.JumpRead(infoB[1:n], 0, finder.RECORD_MAX_SIZE, finder.ReadForward)
		}
	}
	utils.DebugPrint("result", infoA, infoB)
	return
}

func (p *IpWry) Find(ip string) (info string, err error) {
	var idxData []byte
	target := utils.Ip2Bytes(ip)
	if idxData, err = p.SearchIndex(target); err != nil {
		return
	}
	posData := idxData[len(target):]
	p.JumpTo(posData, []byte{0x00}, false)
	var tailData []byte
	tailData, err = p.JumpRead(posData, len(target), 0, finder.ReadForward)
	if utils.Compare(target, tailData, p.IsBom) > 0 {
		return
	}
	var infoA, infoB []byte
	if infoA, infoB, err = p.GetRecord(); err == nil {
		infoA, infoB = utils.DecodeGBK(infoA), utils.DecodeGBK(infoB)
	}
	info = string(infoA)
	if infoB != nil {
		info += " " + string(infoB)
	}
	return
}
